En este capítulo aprenderemos a realizar un análisis exploratorio de datos utilizando R, este proceso es importante ya que nos permite identificar algunas relaciones entre las variables. El análisis exploratorio permite que nos hagamos preguntas y tratar de encontrar respuestas a estas preguntas.
Cómo se menciono anteriormente, en muchas ocasiones es necesario manipular nuestros datos para poder realizar el análisis que deseamos, o limpiar valores no creibles, por ejemplo datos atípicos o valores perdidos por no respuesta.
Antes de comenzar a manipular datos, es necesario comenzar nuestro script utilizando los consejos que se dieron en capítulos anteriores:
Para este capítulo estaremos utilizado las librerías dplyr y tidyverse. La base de datos que utilizaremos es también la Encuesta sobre Ingresos y Gastos de los Hogares.
Añadiremos a nuestro entorno la siguiente instrucción options(scipen=999), la cual desactivara la notación cientifica, a pesar de que no se esten manejando números grandes, R de manera predeterminada trata de simplificar la visualización de números, sin embargo a veces esto puede ser un inconviente, por el momento desativaremos esta notación.
setwd("~/01 Miike Documentos/02 Clases/Curso R/Capítulo 4")
rm(list=ls())
library (tidyverse)
library(dplyr)
library(readr)
options(scipen=999)
enigh <- read_csv("hogares_enigh.csv")
El objetivo del análisis exploratorio de los datos es desarrollar un entendimiento de nuestros datos. La mejor manera de hacer estos es usar preguntas que sirvan de guía para nuestra investigación. Al realizar estas preguntas, estas centran nuestra atención a una parte especifica de nuestro conjunto de datos y nos ayudan a decidir que gráficas, modelos o transformaciones debemos hacer.
Es difícil realizar preguntas reveladoras o que detonen un punto central de una investigación si precisamente no conocemos a detalle nuestros, sin embargo, la idea de este proceso es hacer preguntas sencillas, las cuales relevaran nuevos aspectos de nuestros datos, y generar nuevas preguntas.
Si bien, no hay una regla o guía escrita para comenzar nuestro análisis, un punto de como empezar es a través de dos preguntas:
Para tener un mejor entendimiento es necesario definir algunos conceptos: * Variable: Se refiere a la cantidad, calidad o propiedad medible * Valor: Es el valor de una variable cuando es medida * Observación: Es la unidad individual de nuestro estudio, una observación contiene diferentes valores, cada uno asociado a diferentes variables * Tabla de datos: Es el conjunto de valores, asociados a una variable u observación. Una tabla de datos se caracteriza por tener cada observación en su propia fila y cada variable en su propia columna
Una variación es la tendencia de los valores de una variable a cambiar de medida en medida. Cuando medimos una variable continua dos veces, como la temperatura, podemos obtener dos resultados distintos, cada vez que realizamos una medida obtendremos un pequeño margen de error que varia entre cada medición. Las variables categóricas también pueden variar de medida entre diferentes sujetos, cada variable tiene su propio patrón de variación, las cuales pueden revelar información interesante, la mejor forma de comenzar es visualizar la distribución de nuestras variables de interés.
Anteriormente dimos pocos detalles sobre la encuesta enigh que valdría la pena mencionar ahora. La encuesta esta diseñada para obtener información sobre los patrones de ingresos y gastos de los hogares de manera trimestral, por ende, la unidad de observación son los hogares mexicanos. Cada observación o fila de nuestros datos representa un hogar. Además de eso, recaba información sobre las características demográficas de los integrantes del hogar, aunque en la base de datos solo se incluyen los datos del jefe del hogar.
Comencemos nuestro análisis realizando una distribución del total de integrantes del hogar. En este caso nuestra variable es númerica discreta, para examinar esta distribución usemos una gráfica de barras:
ggplot(data=enigh) +
geom_bar(mapping=aes(x=tot_integ))
La figura anterior se conoce como histograma, un tipo de gráfica que consiste en barras que igual anchura, el eje x representa clases de valores, y el eje y representa sus frecuencias. Los histogramas nos permiten conocer la distribución de los datos, muestra el centro de los datos, la dispersión y nos permite identificar valores atípicos.
En nuestro ejemplo, se observa que la mayoría de los hogares tienen entre 4 y 4 integrantes. Otra forma de calcular estos valores manualmente es con la instrucción contar, de esta forma obtenemos una lista con la cantidad de integrantes y la cantidad de hogares que tienen ese número de integrantes.
enigh %>%
count(tot_integ)
# Resultados omitidos
Ahora vemos el histograma de una variable continua, en este caso consideremos el ingreso promedio trimestral de los hogares, variable ing_cor de nuestros datos:
ggplot(data=enigh)+
geom_histogram(mapping = aes( x= ing_cor), binwidth = 1000)
En este caso añadimos la opción bindidth para especificar el tamaño de la clase, es decir, agrupa los valores en clases de 1000 en 1000. Si utilizamos la forma manual, podemos ver el rango de cada clase:
enigh %>%
count(cut_width(ing_cor,1000))
# Resultado omitido
Lo primero que notamos al observar el histograma es la existencia de valores atípicos, es decir, la existencia de pocos hogares con niveles de ingreso muy altos, los cuales distorsionan la visualización del histograma. Los datos atípicos son aquellos que se encuentran muy alejados de los demás valores de la muestra.
La visualización anterior no permite identificar el nivel de ingreso central de los hogares, por lo que debemos recortar la muestra para poder obtener una mejor visualización sin los efectos de los valores atípicos, proveemos filtrando los datos mayores a un millón:
ingresos<- enigh %>%
filter(ing_cor<1000000)
ggplot(data=ingresos)+
geom_histogram(mapping = aes( x= ing_cor), binwidth = 1000)
Ahora provemos filtrando los hogares con ingresos mayores a 200,000 pesos al trimestre:
ingresos<- enigh %>%
filter(ing_cor<200000)
ggplot(data=ingresos)+
geom_histogram(mapping = aes( x= ing_cor), binwidth = 1000)
Ahora veamos como sobreponer diferentes histogramas en una misma gráfica, en este caso en vez de barras utilizaremos una linea para dibujar cada histograma, esto mejorará la visualización.
En nuestros datos encontraremos la variable clase_hog, la cual nos indica el tipo de hogar según la relación familiar de los integrantes, la variable aunque es categórica, se encuentra codificada, antes de hacer una gráfica es necesario reemplazarla por los valores correspondientes. En este caso no queremos generar una nueva variable, sino reemplazar los valores de una variable existente, para ello utilizaremos la función gsub. (Dado que los valores se encuentran codificados recuerde consultar el descriptor de variables para conocer el significado de cada valor).
# Reemplazamos la variable de tipo de hogar
ingresos$clase_hog <- gsub(1, "Unipersonal", ingresos$clase_hog)
ingresos$clase_hog <- gsub(2, "Nuclear", ingresos$clase_hog)
ingresos$clase_hog <- gsub(3, "Ampliado", ingresos$clase_hog)
ingresos$clase_hog <- gsub(4, "Compuesto", ingresos$clase_hog)
ingresos$clase_hog <- gsub(5, "Corresidente", ingresos$clase_hog)
ggplot(data = ingresos, mapping = aes(x = ing_cor, color = clase_hog)) +
geom_freqpoly(binwidth = 1000)
# Valores típicos Como seguramente han podido inferir de los ejemplos anteriores, los histogramas son muy sensibles a valores atípicos, esto hace que nuestros gráficos se vean sesgados y no podemos apreciar con facilidad los valores centrales, es decir, los valores más comunes de nuestra variable de interés.
Ahora hagamos un histograma con la variable ingtrab la cual indica el promedio trimestral de ingreso por trabajo de los hogares.
ggplot(data=enigh)+
geom_histogram(mapping = aes( x= ingtrab), binwidth = 1000)
La visualización por si misma nos dice poco, de nuevo tenemos valores atípicos que dificultan encontrar los valores centrales. Probemos ahora realizando un “acercamiento” a los valores entre 0 y 200,000 pesos, para ello utilizamos la opción “coord_cartesian”:
ggplot(enigh) +
geom_histogram(mapping = aes(x = ingtrab), binwidth = 1000) +
coord_cartesian(xlim = c(0, 150000))
La opción “coord_cartesian” permite recortar el eje x con el argumento xlim, también podemos recortar el eje y con el argumento ylim en caso de que requiera.
Notas algo incongruente en la gráfica, existe un valor que se repite muchas veces, el cero, si revisamos nuestra variable, notaremos que existen hogares que declaran cero ingreso por trabajo. Provemos filtrar estos datos en nuevo data frame, tanto los valores cero como aquellos mayores a 150,000:
ingresos_trabajo <- enigh %>%
filter(ingtrab >0 & ingtrab < 150000)
ggplot(ingresos_trabajo) +
geom_histogram(mapping = aes(x = ingtrab), binwidth = 10000)
Finalmente podemos decir que los valores centrales de los ingresos por trabajo son alrededor de 30,000 pesos al trimestre.
Ahora combinemos esta información con el sexo del jefe del hogar para observar si existen diferencias entre hogares con jefatura masculina y femenina:
ingresos_trabajo$sexo_jefe <- gsub(1, "Hombre", ingresos_trabajo$sexo_jefe)
ingresos_trabajo$sexo_jefe <- gsub(2, "Mujer", ingresos_trabajo$sexo_jefe)
ggplot(data = ingresos_trabajo, mapping = aes(x = ingtrab, color = sexo_jefe))+
geom_freqpoly(binwidth = 2000)
¿Qué podemos concluir de la gráfica anterior?
Anteriormente observamos que existen valores atípicos en nuestra muestra y para poder analizar un histograma fue necesario filtrar nuestros datos o recortar el eje del gráfico. En ocasiones sera necesario realizar esta acción para diferentes variables y generar un nuevo data frame cada vez que realizamos un cambio es poco eficiente. Por ello es aconsejable realizar estos cambios sobre un mismo conjunto de datos, la forma más fácil de tratar con datos atípicos es eliminarlos, sin embargo, puede ser posible que no deseemos eliminar todas estas observaciones sino más bien solo algunos casos de diferentes variables.
Anteriormente vimos que el ingreso corriente contiene ceros, ya sea por no respuesta o porque en realidad un hogar declaro tener cero ingreso, también observamos que existen pocos hogares con niveles de ingreso muy altos.
A continuación aprenderemos como reemplazar estos valores por valores perdidos, como su nombre lo indica, un valor perdido equivale a una valor omitido o inexistente por lo tanto R ignora estos casos y se visualizan con una etiqueta “NA” siglas del ingles “No disponible”.
enigh <- enigh %>%
mutate(ing_cor = ifelse(ing_cor==0 | ing_cor>200000 , NA, ing_cor))
Ahora si realizamos un gráfico de dispersión entre el ingreso corriente del hogar y la edad del jefe del hogar, notaremos una advertencia sobre la cantidad de valores perdidos que se estan ignorando:
ggplot(data = enigh, mapping = aes(x = edad_jefe, y = ing_cor )) +
geom_point()
## Warning: Removed 937 rows containing missing values (geom_point).
Para evitar estas advertencias es necesario utilizar la instrucción na.rm = TRUE
ggplot(data = enigh, mapping = aes(x = edad_jefe, y = ing_cor)) +
geom_point(na.rm = TRUE)
# Covariacion La covariación se refiere al comportamiento entre variables, es decir, la tendencia de los valores de dos variables o más a variar. La mejor manera de entender este concepto es visualizar la relación entre dos variables.
Antes de continuar, limpiemos nuestro ambiente de trabajo y realicemos los cambios necesarios a nuestro data frame enigh, recordemos que es mejor reemplazar los valores en nuestra misma base de datos que generar nuevos conjuntos.
remove (ingresos, ingresos_trabajo)
enigh <- enigh %>%
mutate(sexo_jefe = ifelse(sexo_jefe==1 , "Hombre", sexo_jefe)) %>%
mutate(sexo_jefe = ifelse(sexo_jefe==2 , "Mujer", sexo_jefe)) %>%
mutate(clase_hog = ifelse(clase_hog==1 , "Unipersonal", clase_hog)) %>%
mutate(clase_hog = ifelse(clase_hog==2 , "Nuclear", clase_hog)) %>%
mutate(clase_hog = ifelse(clase_hog==3 , "Ampliado", clase_hog)) %>%
mutate(clase_hog = ifelse(clase_hog==4 , "Compuesto", clase_hog)) %>%
mutate(clase_hog = ifelse(clase_hog==5 , "Corresidente", clase_hog))
Tal como lo hicimos anteriormente, analizamos el ingreso de los hogares por según la clase de hogar y sexo, sin embargo, en los histogramas, dado que estamos analizando la frecuencia, no podemos apreciar de manera clara las diferencias entre el ingreso según la clase del hogar. Lo que observamos es que hay muchos hogares de tipo nuclear y muy pocos hogares del tipo corresidente y compuesto:
ggplot(data = enigh, mapping = aes(x = ing_cor)) +
geom_freqpoly(mapping = aes(color = clase_hog), binwidth = 10000)
## Warning: Removed 937 rows containing non-finite values (stat_bin).
En efecto, existen diferencias en el tamaño de cada grupo de clase de hogares, algunos grupos son mucho más pequeños que otros. Es difícil ver las diferencias en los histogramas cuando el tamaño de cada grupo es muy diferente.
ggplot(data=enigh)+
geom_bar(mapping = aes(x=clase_hog, y=..prop.., group=1))
Para poder realizar una mejor comparación si realizamos un histograma pero en vez de mostrar la frecuencia en el eje vertical, mostramos la densidad, la cual indica el frecuencia estandarizada, de tal manera que el área bajo cada curva es igual a uno.
Si realizamos el histograma de esta manera, obtenemos una visualización mejor y por ende, podemos describir mejor nuestros, ¿qué observamos?
ggplot(
data = enigh,
mapping = aes(x = ing_cor, y = ..density..)
) +
geom_freqpoly(mapping = aes(color = clase_hog), binwidth = 10000)
## Warning: Removed 937 rows containing non-finite values (stat_bin).
Existe otro factor endógeno que puede alterar la distribución del ingreso, que es el tamaño del hogar. Hogares con mayor número de habitantes tendrán mayor nivel de ingreso, no porque posean mayor riqueza, sino porque un mayor número de personas participaran en actividades remuneradas y por ende aumentará el ingreso total del hogar. Para corregir esta situación necesitamos analizar el ingreso per cápita, de esta forma tendremos un mejor indicador del nivel de ingreso de cada hogar.
enigh <- enigh %>%
mutate(ingreso_per_capita = ing_cor/tot_integ )
ggplot(
data = enigh,
mapping = aes(x = ingreso_per_capita, y = ..density..)
) +
geom_freqpoly(mapping = aes(color = clase_hog), binwidth = 10000)
## Warning: Removed 937 rows containing non-finite values (stat_bin).
Finalmente una manera sencilla de resumir información entre categorías es con un diagrama de caja.
** Faltan detalles **
Con el siguiente diagrama de caja observamos el comportamiento del ingreso per cápita por clase de hogar:
ggplot(data = enigh, mapping = aes(x = clase_hog, y = ingreso_per_capita)) +
geom_boxplot()
## Warning: Removed 937 rows containing non-finite values (stat_boxplot).
# Dos variables categoricas
Para visualizar la covariación entre variables categoricas necesitamos contar el número de observaciones para cada combinación.
Analicemos la distribución de los hogares por nivel educativo del jefe del hogar:
enigh <- enigh %>%
mutate(educa_jefe = ifelse(educa_jefe=="01" , "Sin instrucción", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="02" , "Preescolar", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="03" , "Primaria incompleta", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="04" , "Primaria completa", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="05" , "Secundaria incompleta", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="06" , "Secundaria completa", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="07" , "Preparatoria incompleta", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="08" , "Preparatoria completa", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="09" , "Profesional incompleta", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="10" , "Presional completa", educa_jefe)) %>%
mutate(educa_jefe = ifelse(educa_jefe=="11" , "Posgrado", educa_jefe))
Ahora contamos el número de hogares en cada grupo, una forma sencilla a través de una gráfica de puntos, donde cada circulo representa cuantos hogares existen en cada combinación de variables.
ggplot(data = enigh) +
geom_count(mapping = aes(x = clase_hog, y = educa_jefe))
Otra manera de ver el conteo es de forma tabular, usando la función count():
enigh %>%
count(educa_jefe, clase_hog)
## # A tibble: 54 x 3
## educa_jefe clase_hog n
## <chr> <chr> <int>
## 1 Posgrado Ampliado 182
## 2 Posgrado Compuesto 3
## 3 Posgrado Corresidente 9
## 4 Posgrado Nuclear 864
## 5 Posgrado Unipersonal 204
## 6 Preescolar Ampliado 25
## 7 Preescolar Compuesto 1
## 8 Preescolar Nuclear 37
## 9 Preescolar Unipersonal 14
## 10 Preparatoria completa Ampliado 1488
## # ... with 44 more rows
Finalmente, una forma más atractiva de ver el tamaño de los grupos es usando un mapa de calor:
enigh %>%
count(educa_jefe , clase_hog) %>%
ggplot(mapping = aes(x = clase_hog , y = educa_jefe)) +
geom_tile(mapping = aes(fill = n))
enigh %>%
count(educa_jefe , sexo_jefe) %>%
ggplot(mapping = aes(x = sexo_jefe , y = educa_jefe)) +
geom_tile(mapping = aes(fill = n))
# Dos variables continuas
Una de las mejores gráficas para visualizar la relación entre dos variables es a través de una gráfica de dispersión, la cual ya hemos utilizado con anterioridad. En esta gráfica podemos observar la asociación entre variables, consideremos el ejemplo del ingreso per cápita del hogar y la edad del jede del hogar:
ggplot(data = enigh) +
geom_point(mapping = aes(x = edad_jefe, y = ingreso_per_capita))
## Warning: Removed 937 rows containing missing values (geom_point).
Podemos agregar transparencia para evitar que nuestra visualización se sature (debido al número de observaciones), la transparencia nos permite observar mejor en donde se concentran los valores, se intuye que el ingreso aumenta hasta alrededor de los 60 años y comienza a decender.
ggplot(data = enigh) +
geom_point(
mapping = aes(x = edad_jefe, y = ingreso_per_capita),
alpha = 1 / 100
)+
coord_cartesian(ylim = c(0, 100000))
## Warning: Removed 937 rows containing missing values (geom_point).
Finalmente, si aún no podemos observar un patrón claro en nuestras variables, podemos agrupar una variable continua para observar cambios entre grupos, como si fuera una variable categórica, por ejemplo, realicemos un diagrama de dispersión, pero agrupando a los hogares en grupos de edad de 5 en 5 años, la instrucción cut_width() nos permite indicar el tamaño de cada grupo:
ggplot(data = enigh, mapping = aes(x = edad_jefe, y = ingreso_per_capita)) +
geom_boxplot(mapping = aes(group = cut_width(edad_jefe, 5))) + coord_cartesian(ylim = c(0, 50000))
## Warning: Removed 937 rows containing non-finite values (stat_boxplot).
En cambio, si deseamos que cada grupo tenga aproximadamente el mismo número de observaciones, podemos utilizar la instrucción cut_number(), para indicar el número de clases o grupos que necesitamos y los agrupa de manera automática:
ggplot(data = enigh, mapping = aes(x = edad_jefe, y = ingreso_per_capita)) +
geom_boxplot(mapping = aes(group = cut_number(edad_jefe, 5))) + coord_cartesian(ylim = c(0, 50000))
## Warning: Removed 937 rows containing non-finite values (stat_boxplot).
# Actividades
enigh <-enigh %>%
mutate(cve_ent = substr(ubica_geo,1,2))
library(plotly)
## Warning: package 'plotly' was built under R version 3.6.3
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
plot <- ggplot(data = enigh, mapping = aes(x = cve_ent, y = ingreso_per_capita)) +
geom_boxplot()
ggplotly(plot)
## Warning: Removed 937 rows containing non-finite values (stat_boxplot).
plot <- ggplot(enigh, aes(x = edad_jefe, y = ingreso_per_capita)) + geom_point() +
geom_smooth(method = "lm") + theme_bw()
ggplotly(plot)
## `geom_smooth()` using formula 'y ~ x'
## Warning: Removed 937 rows containing non-finite values (stat_smooth).